]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
runDialog: popModal before running the command
authorDan Winship <danw@gnome.org>
Fri, 18 Mar 2011 15:28:18 +0000 (11:28 -0400)
committerDan Winship <danw@gnome.org>
Mon, 21 Mar 2011 18:26:08 +0000 (14:26 -0400)
If you run a command from Alt+F2 that tries to get a server grab (eg,
xmag), it will fail if it starts up before the run dialog is finished
hiding.

Additionally, the run dialog currently stays focused while it is
fading out, potentially stealing keystrokes (or causing the user to
accidentally launch two copies of a program).

Change ModalDialog.close() to call popModal() immediately

Add a ModalDialog.popModal method, and call that before running the
RunDialog command. If the command succeeds, close the dialog as
before. If it fails, call ModalDialog.pushModal() to put things back
to normal before displaying the error.

https://bugzilla.gnome.org/show_bug.cgi?id=644857

js/ui/modalDialog.js
js/ui/runDialog.js

index 56bc1a2033108770f2a03d5540acdda340819be7..cba0b725bbc1133f43df48d100dbe69d0e110e62 100644 (file)
@@ -39,6 +39,7 @@ ModalDialog.prototype = {
         params = Params.parse(params, { styleClass: null });
 
         this.state = State.CLOSED;
+        this._hasModal = false;
 
         this._group = new St.Group({ visible: false,
                                      x: 0,
@@ -46,6 +47,7 @@ ModalDialog.prototype = {
         Main.uiGroup.add_actor(this._group);
         global.focus_manager.add_group(this._group);
         this._initialKeyFocus = this._group;
+        this._savedKeyFocus = null;
 
         this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
 
@@ -60,12 +62,18 @@ ModalDialog.prototype = {
         this._group.add_actor(this._backgroundBin);
         this._lightbox.highlight(this._backgroundBin);
 
+        this._backgroundStack = new Shell.Stack();
+        this._backgroundBin.child = this._backgroundStack;
+
+        this._eventBlocker = new Clutter.Group({ reactive: true });
+        this._backgroundStack.add_actor(this._eventBlocker);
+
         this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
                                                 vertical:    true });
         if (params.styleClass != null) {
             this._dialogLayout.add_style_class_name(params.styleClass);
         }
-        this._backgroundBin.child = this._dialogLayout;
+        this._backgroundStack.add_actor(this._dialogLayout);
 
         this.contentLayout = new St.BoxLayout({ vertical: true });
         this._dialogLayout.add(this.contentLayout,
@@ -148,7 +156,6 @@ ModalDialog.prototype = {
         this._lightbox.show();
         this._group.opacity = 0;
         this._group.show();
-        this._initialKeyFocus.grab_key_focus();
         Tweener.addTween(this._group,
                          { opacity: 255,
                            time: OPEN_AND_CLOSE_TIME,
@@ -169,7 +176,7 @@ ModalDialog.prototype = {
         if (this.state == State.OPENED || this.state == State.OPENING)
             return true;
 
-        if (!Main.pushModal(this._group, timestamp))
+        if (!this.pushModal(timestamp))
             return false;
 
         this._fadeOpen();
@@ -180,14 +187,8 @@ ModalDialog.prototype = {
         if (this.state == State.CLOSED || this.state == State.CLOSING)
             return;
 
-        let needsPopModal;
-
-        if (this.state == State.OPENED || this.state == State.OPENING)
-            needsPopModal = true;
-        else
-            needsPopModal = false;
-
         this.state = State.CLOSING;
+        this.popModal(timestamp);
 
         Tweener.addTween(this._group,
                          { opacity: 0,
@@ -197,13 +198,46 @@ ModalDialog.prototype = {
                                function() {
                                    this.state = State.CLOSED;
                                    this._group.hide();
-
-                                   if (needsPopModal)
-                                       Main.popModal(this._group, timestamp);
                                })
                          });
     },
 
+    // Drop modal status without closing the dialog; this makes the
+    // dialog insensitive as well, so it needs to be followed shortly
+    // by either a close() or a pushModal()
+    popModal: function(timestamp) {
+        if (!this._hasModal)
+            return;
+
+        let focus = global.stage.key_focus;
+        if (focus && this._group.contains(focus))
+            this._savedKeyFocus = focus;
+        else
+            this._savedKeyFocus = null;
+        Main.popModal(this._group, timestamp);
+        global.gdk_screen.get_display().sync();
+        this._hasModal = false;
+
+        this._eventBlocker.raise_top();
+    },
+
+    pushModal: function (timestamp) {
+        if (this._hasModal)
+            return true;
+        if (!Main.pushModal(this._group, timestamp))
+            return false;
+
+        this._hasModal = true;
+        if (this._savedKeyFocus) {
+            this._savedKeyFocus.grab_key_focus();
+            this._savedKeyFocus = null;
+        } else
+            this._initialKeyFocus.grab_key_focus();
+
+        this._eventBlocker.lower_bottom();
+        return true;
+    },
+
     // This method is like close, but fades the dialog out much slower,
     // and leaves the lightbox in place. Once in the faded out state,
     // the dialog can be brought back by an open call, or the lightbox
@@ -222,6 +256,7 @@ ModalDialog.prototype = {
         if (this.state == State.FADED_OUT)
             return;
 
+        this.popModal(timestamp);
         Tweener.addTween(this._dialogLayout,
                          { opacity: 0,
                            time:    FADE_OUT_DIALOG_TIME,
@@ -229,7 +264,6 @@ ModalDialog.prototype = {
                            onComplete: Lang.bind(this,
                                function() {
                                    this.state = State.FADED_OUT;
-                                   Main.popModal(this._group, timestamp);
                                })
                          });
     }
index 427979722dc3f2aff5bfa3e816cc5861da399453..f239ec821a46e3e7eeb3d07c81e9241b11a6b480 100644 (file)
@@ -240,15 +240,20 @@ __proto__: ModalDialog.ModalDialog.prototype,
         this._entryText.connect('key-press-event', Lang.bind(this, function(o, e) {
             let symbol = e.get_key_symbol();
             if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
+                this.popModal();
                 if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
                     this._run(o.get_text(), true);
                 else
                     this._run(o.get_text(), false);
                 if (!this._commandError)
-                    this.close(global.get_current_time());
+                    this.close();
+                else {
+                    if (!this.pushModal())
+                        this.close();
+                }
             }
             if (symbol == Clutter.Escape) {
-                this.close(global.get_current_time());
+                this.close();
                 return true;
             }
             if (symbol == Clutter.slash) {